package top.malaoshi.webmvc;

import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.multipart.MultipartFile;
import top.malaoshi.webmvc.info.MethodInfo;
import top.malaoshi.webmvc.info.MethodsArgumentInfo;
import top.malaoshi.webmvc.parameter.*;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.io.IOException;
import java.lang.annotation.Annotation;
import java.lang.reflect.Array;
import java.lang.reflect.Method;
import java.util.List;
import java.util.Map;

/**
 * 解析方法形参
 */
public class MethodArgumentResolver {

    static NoneResolver noneResolver = new NoneResolver();
    static HttpRequestResolver requestResolver = new HttpRequestResolver();
    static HttpResponseResolver responseResolver = new HttpResponseResolver();
    static HttpSessionResolver sessionResolver = new HttpSessionResolver();
    static StringResolver stringResolver = new StringResolver();
    static StringArrayResolver stringArrayResolver = new StringArrayResolver();
    /**
     * 数组类型是基本数据类型的解析器
     */
    static BaseTypeArrayResolver baseTypeArrayResolver = new BaseTypeArrayResolver();
    static ListResolver listResolver = new ListResolver();
    static BeanResolver beanResolver = new BeanResolver();
    static BaseTypeResolver baseTypeResolver = new BaseTypeResolver();
    // 基本数据类型数组
    static BaseTypeWrapperResolver baseTypeWrapperResolver = new BaseTypeWrapperResolver();
    // 基本数据类型的包装类型数组
    static BaseTypeWrappeArrayrResolver baseTypeWrappeArrayrResolver = new BaseTypeWrappeArrayrResolver();
    static MapResolver mapResolver = new MapResolver();
    static JsonResolver jsonResolver = new JsonResolver();
    static MultipartResolver multipartResolver = new MultipartResolver();
    static MultipartArrayResolver multipartArrayResolver = new MultipartArrayResolver();

    static void handler(Method method, MethodInfo mi) throws IOException {


        Class<?>[] parameterTypes = method.getParameterTypes();
        Annotation[][] parameterAnnotations = method.getParameterAnnotations();
//        String className = method.getDeclaringClass().getName();
//        String[] names = MethodArgumentNameResolver.handler(method.getDeclaringClass(), method.getName());
        String[] names = MethodArgumentNameResolver2.handle(method);

        for(int i = 0,len = parameterTypes.length;i<len;i++){
            Annotation[] parameterAnnotation = parameterAnnotations[i];
            // 形参前有注解
            if(parameterAnnotation!=null && parameterAnnotation.length>0){

                Annotation requestParamAnn = getAnn(parameterAnnotation, RequestParam.class);
                Annotation requestBodyAnn = getAnn(parameterAnnotation, RequestBody.class);

                if(requestParamAnn != null){
                    RequestParam requestParam = (RequestParam) requestParamAnn;
                    handleRequestParam(mi,requestParam,names,parameterTypes,i);
                }else if(requestBodyAnn != null){
                    RequestBody requestBody = (RequestBody) requestBodyAnn;
                    MethodsArgumentInfo mai = MethodsArgumentInfo.of(names[i],parameterTypes[i],requestBody,i,mi);

                    mi.addArgumentResolvers(jsonResolver);
                    mi.addMethodsArgumentInfo(mai);
                }else{
                    // 形参前没有注解
                    handleRequestParam(mi,null,names,parameterTypes,i);

                }
            }else{
                // 形参前没有注解
                handleRequestParam(mi,null,names,parameterTypes,i);

            }

        }
    }
    private static Annotation getAnn(Annotation[] annotations , Class<?> annotationClass){
        for(Annotation item : annotations){
            if(annotationClass.isInstance(item)){
                return item;
            }
        }
        return null;
    }
    private static void handleRequestParam(MethodInfo mi,RequestParam requestParam,String[] names,Class[] parameterTypes,int i){
        MethodsArgumentInfo mai = MethodsArgumentInfo.of(names[i],parameterTypes[i],requestParam,i,mi);

        if(parameterTypes[i] == String.class || parameterTypes[i] == Object.class ){
            mi.addArgumentResolvers(stringResolver);
        }else if( parameterTypes[i] == short.class ||
                parameterTypes[i] == int.class ||
                parameterTypes[i] == long.class ||
                parameterTypes[i] == float.class ||
                parameterTypes[i] == double.class ||
                parameterTypes[i] == boolean.class){
            mi.addArgumentResolvers(baseTypeResolver);
        }else if(Number.class.isAssignableFrom(parameterTypes[i])){
            mi.addArgumentResolvers(baseTypeWrapperResolver);
        }else if(parameterTypes[i] == Boolean.class){
            mi.addArgumentResolvers(baseTypeWrapperResolver);
        }else if(parameterTypes[i] == HttpServletRequest.class){
            mi.addArgumentResolvers(requestResolver);
        }else if(parameterTypes[i] == HttpServletResponse.class){
            mi.addArgumentResolvers(responseResolver);
        }else if(parameterTypes[i] == HttpSession.class){
            mi.addArgumentResolvers(sessionResolver);
        }else if(parameterTypes[i].isArray()){
            Class clazz = parameterTypes[i].getComponentType();
            mai = MethodsArgumentInfo.of(names[i],Array.class,clazz,requestParam,i,mi);
            if(clazz == String.class){
                mi.addArgumentResolvers(stringArrayResolver);
            }else if ( clazz == int.class ||
                    clazz == short.class ||
                    clazz == long.class ||
                    clazz == float.class ||
                    clazz == double.class ||
                    clazz == boolean.class){
                mi.addArgumentResolvers(baseTypeArrayResolver);
            }else if(clazz == Integer.class ||
                    clazz == Short.class ||
                    clazz == Long.class ||
                    clazz == Float.class ||
                    clazz == Double.class ||
                    clazz == Boolean.class){
                mi.addArgumentResolvers(baseTypeWrappeArrayrResolver);

            }else if(clazz == MultipartFile.class){
                mi.addArgumentResolvers(multipartArrayResolver);
            }else{
                mi.addArgumentResolvers(noneResolver);
            }
        }else if(parameterTypes[i] == List.class ||
                List.class.isAssignableFrom(parameterTypes[i])){
            // 判断形参类型是否 List 或 List实现类
            mi.addArgumentResolvers(listResolver);
        }else if(parameterTypes[i] == Map.class ||
                Map.class.isAssignableFrom(parameterTypes[i])){
            // 判断该类型是否 Map 或 Map 实现类
            mi.addArgumentResolvers(mapResolver);
        }else if(parameterTypes[i] == MultipartFile.class){
            mi.addArgumentResolvers(multipartResolver);
        }else{
            mi.addArgumentResolvers(beanResolver);
        }

        mi.addMethodsArgumentInfo(mai);
    }
}
